#pragma once
#include <map>
#include "CLocalObject.h"
#include "CLComString.h"
#include "CRecordItem.h"

#define CDATAFILE_INVALID_INT_VALUE		-1
#define CDATAFILE_INVALID_DOUBLE_VALUE	-1

#define CDATAFILE_KEY_LEN				64
#define CDATAFILE_MARK_VALUE			1234
#define CDATAFILE_INVALIDMARK_VALUE		4321
#define CDATAFILE_HEADER_LEN			128
#define CDATAFILE_SPLITER				"@||@"
#define CDATAFILE_HEADER_ITEM_COUNT		4

enum DATAFILE_DATA_TYPE
{
	DATAFILE_DATA_TYPE_INT = 0,
	DATAFILE_DATA_TYPE_DOUBLE,
	DATAFILE_DATA_TYPE_STRING,
	DATAFILE_DATA_TYPE_OBJ,
};

enum DATAFILE_CLEAR_TYPE
{
	DATAFILE_CLEAR_TYPE_OLD = 0,
	DATAFILE_CLEAR_TYPE_NEW,
	DATAFILE_CLEAR_TYPE_ALL,
};

struct SDataHeader
{
	int					_nDataLen;
	DATAFILE_DATA_TYPE	_eType;
	int					_nMarkValue;
	char				_czKey[CDATAFILE_KEY_LEN];

	SDataHeader();
	SDataHeader(const SDataHeader& other);
	SDataHeader& operator=(const SDataHeader& other);
};

struct SObjectValue
{
	int		_nDataLen;
    char*	_pObj;

	SObjectValue();
	SObjectValue(const SObjectValue& other);
	SObjectValue& operator=(const SObjectValue& other);
	void DeepCopy(const SObjectValue& other);
};

struct SDataFileHeader
{
    char	_czFileName[256];
	int		_nFileSize;

	SDataFileHeader();
	SDataFileHeader(const SDataFileHeader& other);
	SDataFileHeader& operator=(const SDataFileHeader& other);
};


class CDataFile : public CLocalObject
{
public:
    CDataFile(CLComString filepath);
	~CDataFile();

public:
	static void Copy(CDataFile* pdst, const CDataFile* psrc);

public:
    void GetKeys(map<int, CLComString>& mapkeys);

    int GetIntValue(CLComString key, int nDefault = CDATAFILE_INVALID_INT_VALUE);
    CLComString GetStringValue(CLComString key, CLComString strDefault = "");
    double GetDoubleValue(CLComString key, double dDefault = CDATAFILE_INVALID_DOUBLE_VALUE);
    void* GetPObject(CLComString key);
    int GetPObjectLen(CLComString key);
public:
    void SetIntValue(CLComString key, int nValue);
    void SetStringValue(CLComString key, CLComString strValue);
    void SetDoubleValue(CLComString key, double dValue);
    void SetObject(CLComString key, int nLen, void* pData, bool bDeepcopy);
public:
	bool GoBack(int nIndex = -1);
	bool GoNext(int nIndex = -1);
	int BackUp(CRecordItem& recordinfo);
	void Update();

public:
	void ClearBackup();
	void Save2File(FILE* file);
	void ClearKeys();
	
private:
    bool LoadFile(CLComString filename, bool bOrigin=false);
    void SaveFile(CLComString filename);

	void ReadData(SDataHeader& dataheader, FILE* file);
	void ReadObjData(SDataHeader& dataheader, FILE* file);
	void ReadAbandonData(SDataHeader& dataheader, FILE* file);

    void Trans2Map(SDataHeader& dataheader, CLComString strvalue);

private:
	void ReadAndParseHeader(FILE* file, SDataHeader& dataheader);

    void WriteInt(FILE* file, CLComString key, int nValue);
    void WriteDouble(FILE* file, CLComString key, double dValue);
    void WriteString(FILE* file, CLComString key, CLComString strValue);

    void WriteData(FILE* file, CLComString key, CLComString strValue, DATAFILE_DATA_TYPE dtype);
    void WriteData(FILE* file, CLComString key, SObjectValue& objvalue);

    void WriteDataHeader(FILE* file, CLComString key, DATAFILE_DATA_TYPE dtype, int nLen);

    CLComString TransDataHeader2String(SDataHeader& dataheader);

	void ClearFile(DATAFILE_CLEAR_TYPE eClearType);

private:
	int						m_nIndex;
	int						m_nCurrentIndex;
    CLComString				m_filePath;

    map<CLComString, int>		m_mapIntValue;
    map<CLComString, double>		m_mapDoubleValue;
    map<CLComString, CLComString>	m_mapStringValue;

    map<CLComString, SObjectValue>		m_mapObjects;
};

